﻿using Inovout.Caching;
using Inovout.Descriptors;
using Inovout.Repositories;
using NHibernate.Mapping;
using System;
using System.Linq;
using System.Reflection;

namespace Inovout.Models
{
    public class DataObjectTypeDescriptor : TypeDescriptor
    {
        public PersistentClass NHibernatePersistentClass
        {
            get
            {
                if (nhibernatePersistentClass == null)
                {
                    RepositoryConfigurationKeyDictionary repositoryConfigurationKeyDictionary
                                            = ComponentRegistry.Resolve<RepositoryConfigurationKeyDictionary>();
                    NHibernate.Cfg.Configuration configuration
                     = ComponentRegistry.Resolve<NHibernate.Cfg.Configuration>(
                     repositoryConfigurationKeyDictionary.GetDatabaseName(base.ReflectionType) + ".cfg");
                    nhibernatePersistentClass = configuration.GetClassMapping(base.ReflectionType);

                }
                return nhibernatePersistentClass;
            }
        }
        private PersistentClass nhibernatePersistentClass;
        public DataObjectTypeDescriptor(Type type)
            : base(type)
        {
        }
        protected override PropertyDescriptor CreatePropertyDescriptor(PropertyInfo propertyInfo)
        {
            if (propertyInfo.Name.Equals(NHibernatePersistentClass.IdentifierProperty.Name))
            {
                IdentifierProperty = new DataObjectPropertyDescriptor(propertyInfo, nhibernatePersistentClass.IdentifierProperty);
                return IdentifierProperty;
            }
            else if (NHibernatePersistentClass.PropertyClosureIterator.Count(p =>
      p.Name.Equals(propertyInfo.Name)) == 0)
            {
                return base.CreatePropertyDescriptor(propertyInfo);
            }
            else
            {
                var nhibernateProperty = NHibernatePersistentClass.GetProperty(propertyInfo.Name);
                return new DataObjectPropertyDescriptor(propertyInfo, nhibernateProperty);
            }
        }

        public DataObjectPropertyDescriptor IdentifierProperty
        {
            get;
            private set;
        }
        public new static DataObjectTypeDescriptor Get<TType>() where TType : class
        {
            return Get(typeof(TType));
        }
        private static DictionaryCache<Type, DataObjectTypeDescriptor> typeDescriptorCache = new DictionaryCache<Type, DataObjectTypeDescriptor>();

        public new static DataObjectTypeDescriptor Get(Type type)
        {
            ArgumentAssert.IsNotNull(type, "type");

            return typeDescriptorCache.AddOrGet(type, () => new DataObjectTypeDescriptor(type));

        }
    }
}
